
/**
 * 执行上下文的创建
     创建执行上下文又可以分为两个阶段: 1. 创建阶段 2. 执行阶段
      1. 创建阶段
        在创建阶段，JavaScript引擎会创建LexicalEnvironment(词法环境)组件，VariableEnvironment(变量环境)组件以及this绑定(在全局上下文中，this指向全局对象。在函数执行上下文中，this取决与函数在哪里被调用。)
      2.执行阶段
        在执行阶段，会完成对所有变量的分配，代码也会被最终执行。执行上下文的代码会被分成两个阶段：
          1)进入执行上下文 2)代码执行
 */

// 执行上下文(环境)
export class ExecutionContext {
  constructor(realm, lexicalEnvironment, variableEnvironment){
    //词法环境LexicalEnvironment
    this.lexicalEnvironment = variableEnvironment || lexicalEnvironment
    // var变量存储环境
    this.variableEnvironment = variableEnvironment
    // object,object原型环境
    // this.realm = {
    //   global:{},
    //   Object:{},
    //   Object_prototype:{}
    // }
    this.realm = realm
  }
  
}

// Environment Record环境记录(存储变量和函数声明的实际位置)和对外部环境的引用(可以访问其外部词法环境)
export class EnvironmentRecord{
  constructor(){
    // this.thisValue
    this.variables = new Map();
    this.outer = null;
  }

  add(name) {
    this.variables.set(name, new JSUndefined)
  }

  get(name){
    if(this.variables.has(name)){
      return this.variables.get(name)
    } else if(this.outer){
      return this.outer.get(name)
    } else {
      return JSUndefined
    }
  }

  set(name,value){
    if(this.variables.has(name)){
      return this.variables.set(name,value)
    } else if(this.outer){
      return this.outer.set(name,value)
    } else {
      return this.variables.set(name,value)
    }
  }
}

export class ObjectEnvironmentRecord{
  constructor(object){
    this.object = object;
    this.outer = null
  }

  add(name) {
    this.object.set(name, new JSUndefined)
  }

  get(name){
    return this.object.get(name)
    // todo:with statement need outer
  }

  set(name,value= new JSUndefined){
    this.object.set(name, value)
    // todo:with statement need outer
  }
}

// 运行时JS引擎会创建Reference--所有对象属性的访问等涉及到
export class Reference{
  constructor(object, property){
    this.object = object
    this.property = property
  }

  set(value){
    this.object.set(this.property,value)
  }

  get(){
    return this.object.get(this.property)
  }
}

// Object,Object原型环境
export class Realm{
  constructor(){
    this.global = new Map(),
    this.Object = new Map(),
    this.Object.call = function(){

    }
    this.Object_prototype = new Map()
  }
}

// 基本类型实现 number，string，boolean，null，undefined，object，symbol
export class JSValue{
  // 基类
  get type(){
    if(this.constructor === JSNumber){
      return "number"
    }
    if(this.constructor === JSString){
      return "string"
    }
    if(this.constructor === JSBoolean){
      return "boolean"
    }
    if(this.constructor === JSObject){
      return "object"
    }
    if(this.constructor === JSNull){
      return "null"
    }
    if(this.constructor === JSUndefined){
      return "undefined"
    }
    if(this.constructor === JSSymbol){
      return "symbol"
    }
    return "undefined"
  }
}

export class JSNumber extends JSValue{
  constructor(value){
    super()
    this.memory = new ArrayBuffer(8)
    if(arguments.length)
      new Float64Array(this.memory)[0] = value
    else
      new Float64Array(this.memory)[0] = 0
  }

  get value(){
    return new Float64Array(this.memory)[0]
  }

  toString(){

  }
  toNumber(){
    return this;
  }
  toBoolean(){
    if(new Float64Array(this.memory)[0] === 0){
      return new JSBoolean(false)
    } else{
      return new JSBoolean(true)
    }
  }
}

export class JSString extends JSValue{
  constructor(characters){
    super()
    // this.memory = new ArrayBuffer(characters.length * 2)
    this.characters = characters;
  }

  toString(){
    return this;
  }
  toNumber(){
    
  }
  toBoolean(){
    if(new Float64Array(this.memory)[0] === 0){
      return new JSBoolean(false)
    } else{
      return new JSBoolean(true)
    }
  }

}
export class JSBoolean extends JSValue{
  constructor(value){
    super()
    this.value = value || false;
  }
  toString(){
    if(this.value)
      return new JSString("t","r","u","e")
    else  
      return new JSString("f","a","l","s","e")
  }
  toNumber(){
    if(this.value)
      return new JSNumber(1)
    else  
      return new JSNumber(0)
  }
  toBoolean(){
    return this
  }
  

}
export class JSObject extends JSValue{
  constructor(){
    super()
    this.properties = new Map()
    this.prototype = proto || null
  }

  set(name, value){
    this.setProperty(name,{
      value: value,
      enumerable: true,
      configurable: true,
      writeable: true
    })
  }

  get(name){
    // todo: prototype chain && getter
    return this.getProperty(name)
  }

  setProperty(name, attributes){
    this.properties.set(name, attributes)
  }

  getProperty(name){
    // todo --需要原型
    this.properties.get(name)
  }

  getPrototype(){
    return this.prototype
  }
  setPrototype(proto){
    this.prototype = proto
  }

  getPrototype(){
    return this.prototype
  }
}

export class JSNull extends JSValue{
  constructor(){
    super()
  }
  toString(){
    return new JSString("n","u","l","l")
  }
  toNumber(){
    return new JSNumber(0)
  }
  toBoolean(){
    return new JSBoolean(false)
  }
}
export class JSUndefined extends JSValue{
  toString(){
    return new JSString("u","n","d","e","f","i","n","e","d")
  }
  toNumber(){
    return new JSNumber(NaN)
  }
  toBoolean(){
    return new JSBoolean(false)
  }
}
export class JSSymbol extends JSValue{
  constructor(name){
    super()
    this.name = name || ""
  }
}



/**完成记录类型,涉及到break，return，continue时js引擎有调用到 */
export class CompletionRecord{
  constructor(type, value ,target){
    this.type = type || 'normal'
    this.value = value || new JSUndefined;
    this.target = target || null;
  }
}

